//********************************************************************
//	created:	13:2:2012   15:01
//	filename: 	xmlrpcvalue.h
//	author:		tiamo
//	purpose:	xmlrpc value
//********************************************************************

#pragma once

//
// xmlrpc
//
namespace xmlrpc
{
	//
	// value
	//
	class Value : public utils::RefCountedObject
	{
	public:
		//
		// type
		//
		enum
		{
			//
			// null
			//
			TypeNull,

			//
			// i4
			//
			TypeI4,

			//
			// i8
			//
			TypeI8,

			//
			// boolean
			//
			TypeBoolean,

			//
			// double
			//
			TypeDouble,

			//
			// datetime
			//
			TypeDateTime,

			//
			// string
			//
			TypeString,

			//
			// byte buffer
			//
			TypeByteBuffer,

			//
			// array
			//
			TypeArray,

			//
			// struct
			//
			TypeStruct,
		};

	public:
		//
		// constructor
		//
		Value(uint32_t type)												{mType = type;}

		//
		// destructor
		//
		virtual ~Value()													{}

		//
		// encode
		//
		virtual UniString encode()  const									{return L"<nil />";}

		//
		// get i4
		//
		int32_t getI4() const;

		//
		// get i8
		//
		int64_t getI8() const;

		//
		// get boolean
		//
		bool getBoolean() const;

		//
		// get double
		//
		double getDouble() const;

		//
		// get string
		//
		UniString const& getString() const;

		//
		// get count
		//
		uint32_t getCount() const;

		//
		// get
		//
		Value const* get(uint32_t index) const;

		//
		// has
		//
		Value const* has(UniString const& key) const;

		//
		// get
		//
		Value const* get(UniString const& key) const;

		//
		// get i4
		//
		int32_t getI4(uint32_t index) const									{return get(index)->getI4();}

		//
		// get i8
		//
		int64_t getI8(uint32_t index) const									{return get(index)->getI8();}

		//
		// get boolean
		//
		bool getBoolean(uint32_t index) const								{return get(index)->getBoolean();}

		//
		// get double
		//
		double getDouble(uint32_t index) const								{return get(index)->getDouble();}

		//
		// get string
		//
		UniString const& getString(uint32_t index) const					{return get(index)->getString();}

		//
		// get i4
		//
		int32_t getI4(UniString const& key) const							{return get(key)->getI4();}

		//
		// get i8
		//
		int64_t getI8(UniString const& key) const							{return get(key)->getI8();}

		//
		// get boolean
		//
		bool getBoolean(UniString const& key) const							{return get(key)->getBoolean();}

		//
		// get double
		//
		double getDouble(UniString const& key) const						{return get(key)->getDouble();}

		//
		// get string
		//
		UniString const& getString(UniString const& key) const				{return get(key)->getString();}

	protected:
		//
		// type check
		//
		void typeCheck(int32_t needType) const								{if(needType!=mType)ThrowXmlRpcException(Exception::TypeError, L"type mismatch (%d!=%d)", needType, mType);}

	protected:
		//
		// type
		//
		int32_t																mType;
	};

	//
	// i4 value
	//
	class I4Value : public Value
	{
	public:
		//
		// constructor
		//
		I4Value(int32_t value) : Value(TypeI4)								{mI4Value = value;}

		//
		// destructor
		//
		virtual ~I4Value()													{}

		//
		// i4
		//
		operator int32_t() const											{return mI4Value;}

	private:
		//
		// encode
		//
		virtual UniString encode() const;

	private:
		//
		// i4 value
		//
		int32_t																mI4Value;
	};

	//
	// i8 value
	//
	class I8Value : public Value
	{
	public:
		//
		// constructor
		//
		I8Value(int64_t value) : Value(TypeI8)								{mI8Value = value;}

		//
		// destructor
		//
		virtual ~I8Value()													{}

		//
		// i8
		//
		operator int64_t() const											{return mI8Value;}

	private:
		//
		// encode
		//
		virtual UniString encode() const;

	private:
		//
		// i8 value
		//
		int64_t																mI8Value;
	};

	//
	// boolean value
	//
	class BooleanValue : public Value
	{
	public:
		//
		// constructor
		//
		BooleanValue(bool value) : Value(TypeBoolean)						{mBooleanValue = value;}

		//
		// destructor
		//
		virtual ~BooleanValue()												{}

		//
		// boolean
		//
		operator bool() const												{return mBooleanValue;}

	private:
		//
		// encode
		//
		virtual UniString encode() const									{return mBooleanValue ? L"<boolean>1</boolean>" : L"<boolean>0</boolean>";}

	private:
		//
		// boolean value
		//
		bool																mBooleanValue;
	};

	//
	// double value
	//
	class DoubleValue : public Value
	{
	public:
		//
		// constructor
		//
		DoubleValue(double value) : Value(TypeDouble)						{mDoubleValue = value;}

		//
		// destructor
		//
		virtual ~DoubleValue()												{}

		//
		// double
		//
		operator double() const												{return mDoubleValue;}

	private:
		//
		// encode
		//
		virtual UniString encode() const;

	private:
		//
		// double value
		//
		double																mDoubleValue;
	};

	//
	// datetime value
	//
	class DateTimeValue : public Value
	{
	public:
		//
		// datetime
		//
		struct DateTime
		{
			//
			// year
			//
			uint16_t														mYear;

			//
			// month
			//
			uint8_t															mMonth;

			//
			// day
			//
			uint8_t															mDay;

			//
			// hour
			//
			uint8_t															mHour;

			//
			// minute
			//
			uint8_t															mMinute;

			//
			// second
			//
			uint8_t															mSecond;

			//
			// us
			//
			uint32_t														mMicroSecond;
		};

	public:
		//
		// constructor
		//
		DateTimeValue() : Value(TypeDateTime)								{memset(&mDateTime, 0, sizeof(mDateTime));}
		//
		// constructor
		//
		DateTimeValue(DateTime const& dateTime) : Value(TypeDateTime), mDateTime(dateTime) {}

		//
		// get datetime
		//
		DateTime const& getDateTime() const									{return mDateTime;}

		//
		// get datetime
		//
		DateTime& getDateTime()												{return mDateTime;}

	private:
		//
		// encode
		//
		virtual UniString encode() const;

	private:
		//
		// datetime
		//
		DateTime															mDateTime;
	};

	//
	// string value
	//
	class StringValue : public Value
	{
	public:
		//
		// constructor
		//
		StringValue(wchar_t const* stringValue) : Value(TypeString), mStringValue(stringValue) {}

		//
		// constructor
		//
		StringValue(UniString const& stringValue) : Value(TypeString), mStringValue(stringValue) {}

		//
		// destructor
		//
		virtual ~StringValue()												{}

		//
		// string
		//
		operator UniString const&() const									{return mStringValue;}

	private:
		//
		// encode
		//
		virtual UniString encode() const									{return L"<string>" + utils::escapeXml(mStringValue) + L"</string>";}

	private:
		//
		// string value
		//
		UniString															mStringValue;
	};

	//
	// byte buffer value
	//
	class ByteBufferValue : public Value
	{
	public:
		//
		// constructor
		//
		ByteBufferValue(void const* byteBuffer, uint32_t bufferLength) : Value(TypeByteBuffer), mDataBuffer(byteBuffer, bufferLength, false) {}

		//
		// constructor
		//
		ByteBufferValue(utils::DataBuffer&& dataBuffer) : Value(TypeByteBuffer), mDataBuffer(std::move(dataBuffer)) {}

		//
		// destructor
		//
		virtual ~ByteBufferValue()											{}

		//
		// get data buffer
		//
		utils::DataBuffer const& getDataBuffer() const						{return mDataBuffer;}

	private:
		//
		// encode
		//
		virtual UniString encode() const;

	private:
		//
		// data buffer
		//
		utils::DataBuffer													mDataBuffer;
	};

	//
	// array value
	//
	class ArrayValue : public Value
	{
	public:
		//
		// array type
		//
		typedef std::vector<utils::SmartPointer<Value>>						ValueType;

	public:
		//
		// constructor
		//
		ArrayValue() : Value(TypeArray)										{}

		//
		// destructor
		//
		virtual ~ArrayValue()												{}

		//
		// get array
		//
		ValueType& getArray()												{return mArrayValue;}

		//
		// get array
		//
		ValueType const& getArray() const									{return mArrayValue;}

	private:
		//
		// encode
		//
		virtual UniString encode() const;

	private:
		//
		// array
		//
		ValueType															mArrayValue;
	};

	//
	// struct value
	//
	class StructValue : public Value
	{
	public:
		//
		// array type
		//
		typedef std::map<UniString, utils::SmartPointer<Value>>				ValueType;

	public:
		//
		// constructor
		//
		StructValue() : Value(TypeStruct)									{}

		//
		// destructor
		//
		virtual ~StructValue()												{}

		//
		// get struct
		//
		ValueType& getStruct()												{return mStructValue;}

		//
		// get struct
		//
		ValueType const& getStruct() const									{return mStructValue;}

	private:
		//
		// encode
		//
		virtual UniString encode() const;

	private:
		//
		// struct
		//
		ValueType															mStructValue;
	};

	//
	// encoder
	//
	class Encoder
	{
	public:
		//
		// constructor
		//
		Encoder()															{}

		//
		// destructor
		//
		~Encoder()															{}

		//
		// encode response
		//
		Utf8String encodeResponse(Value const* r, bool isFault)				{return isFault ? encodeFault(r) : encodeResponse(r);}

	private:
		//
		// encode response
		//
		Utf8String encodeResponse(Value const* response);

		//
		// encode fault
		//
		Utf8String encodeFault(Value const*  fault);

		//
		// encode value
		//
		Utf8String encodeValue(Value const* value)							{return utils::wideToUtf8(value->encode());}
	};

	//
	// decoder
	//
	class Decoder
	{
	public:
		//
		// constructor
		//
		Decoder()															{}

		//
		// destructor
		//
		~Decoder()															{}

		//
		// decode
		//
		void decodeRequest(utils::DataBuffer&& dataBuffer);

		//
		// get method name
		//
		UniString const& getMethodName() const								{return mMethodName;}

		//
		// get param list
		//
		ArrayValue* getParamList() const									{return mParamList.get();}

	private:
		//
		// parse int32
		//
		utils::SmartPointer<Value> parseInt32(UniString const& valueContent);

		//
		// parse int64
		//
		utils::SmartPointer<Value> parseInt64(UniString const& valueContent);

		//
		// parse boolean
		//
		utils::SmartPointer<Value> parseBoolean(UniString const& valueContent);

		//
		// parse double
		//
		utils::SmartPointer<Value> parseDouble(UniString const& valueContent);

		//
		// parse datetime
		//
		utils::SmartPointer<Value> parseDateTime(UniString const& valueContent);

		//
		// parse base64
		//
		utils::SmartPointer<Value> parseBase64(UniString const& valueContent);

		//
		// parse array
		//
		utils::SmartPointer<Value> parseArray(utils::XmlParser& xmlParser, xmlNodePtr typeNode);

		//
		// parse struct
		//
		utils::SmartPointer<Value> parseStruct(utils::XmlParser& xmlParser, xmlNodePtr typeNode);

		//
		// parse value
		//
		utils::SmartPointer<Value> parseValue(utils::XmlParser& xmlParser, xmlNodePtr valueNode);

		//
		// convert param
		//
		utils::SmartPointer<ArrayValue> convertParamArray(utils::XmlParser& xmlParser, xmlNodePtr paramArrayNode);

	private:
		//
		// method name
		//
		UniString															mMethodName;

		//
		// param list
		//
		utils::SmartPointer<ArrayValue>										mParamList;
	};
}
